
#ifndef __M_SESSION_H__
#define __M_SESSION_H__

#include <iostream>
#include "onlineuser.hpp"

enum class statu
{
    LOGIN,
    UNLOGIN
};
//session管理模块
class session
{
    public:
        using ptr=std::shared_ptr<session>;
        session(uint64_t ssid)
        :_ssid(ssid)
        {
            DLOG("session被创建%p",this);
        }
        ~session()
        {
            DLOG("session被释放%p",this);
        }
        //设置用户id
        void setUid(uint64_t uid){_uid=uid;}
        //获取用户id
        uint64_t getUid(){return _uid;}
        //判断用户是否登录
        bool is_login(){return _statu==statu::LOGIN;}
        //设置定时器
        void set_timer(const wsserver_t::timer_ptr& tp){_tp=tp;}
        //获取定时器
        wsserver_t::timer_ptr& get_timer(){return _tp;}
        //获取ssid
        uint64_t get_ssid(){return _ssid;}
        void set_statu(statu stat){_statu=stat;}
    private:
        uint64_t _ssid;//sessionid
        uint64_t _uid;//用户id
        statu _statu;//用户登录状态
        wsserver_t::timer_ptr _tp;//定时器
};

#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
class sessionManager
{
    public:
        //通过wsserver_t设置过期时间
        sessionManager(wsserver_t* server):_next_rid(1),_server(server){
            DLOG("session管理模块初始化成功");
        }
        ~sessionManager(){}
        //创建session
        session::ptr create_session(uint64_t uid,statu stat)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            session::ptr ssp(new session(_next_rid));
            ssp->setUid(uid);
            ssp->set_statu(stat);
            ssp->set_timer(wsserver_t::timer_ptr());//设置一个空的定时器
            _sessions.insert(std::make_pair(_next_rid,ssp));
            _next_rid++;
            return ssp;
        }
        //销毁session
        void remove_session(uint64_t ssid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _sessions.erase(ssid);
        }
        //获取session
        session::ptr get_session(uint64_t sid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_sessions.find(sid);
            if(it==_sessions.end())
            {
                return session::ptr();
            }
            return it->second;
        }
        void append_session(session::ptr& sp)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _sessions.insert(std::make_pair(sp->get_ssid(),sp));
        }
        //设置session的定时器(过期删除)
        void set_expire_time(uint64_t sid,int ms)
        {
            session::ptr ssp=get_session(sid);
            if(ssp.get()==nullptr)
            {
                return ;
            }
            //获取session中的定时器
            wsserver_t::timer_ptr tp=ssp->get_timer();
            //本来定时器为空，表示session永久保存;现在想要设置为永久保存或一段时间后删除
            if(tp.get()==nullptr&&ms==SESSION_FOREVER)
            {
                //永久保存
                return;
            }
            else if(tp.get()==nullptr&&ms!=SESSION_FOREVER)
            {
                //保存一段时间
                wsserver_t::timer_ptr tmp_tp=_server->set_timer(ms,
                        std::bind(&sessionManager::remove_session,this,sid));
                ssp->set_timer(tmp_tp);
            }
            else if(tp.get()!=nullptr&&ms==SESSION_FOREVER)
            {
                //取消之前的定时器
                tp->cancel();//这个函数会立即执行定时器对应的动作(删除session)
                //需要重新将session加入管理
                ssp->set_timer(wsserver_t::timer_ptr());//将定时器置空
                _server->set_timer(0,
                            std::bind(&sessionManager::append_session,this,ssp));
            }
            else if(tp.get()!=nullptr&&ms!=SESSION_FOREVER)
            {
                //取消之前的定时器
                tp->cancel();
                //将当前session重新加入管理
                ssp->set_timer(wsserver_t::timer_ptr());
                _server->set_timer(0,
                            std::bind(&sessionManager::append_session,this,ssp));
                //重新设置过期时间
                wsserver_t::timer_ptr tmp_tp=_server->set_timer(ms,
                            std::bind(&sessionManager::remove_session,this,sid));
                ssp->set_timer(tmp_tp);
            }
        }
    private:
        std::mutex _mutex;
        std::unordered_map<uint64_t,session::ptr> _sessions;
        wsserver_t* _server;
        uint64_t _next_rid;//session分配的id
};

#endif